#include "e2d/core/Entity.h"
#include "e2d/core/Settings.h"

using namespace e2d;


std::vector<e2d::Entity*> e2d::Entity::GetChildrenExistCalculate() const
{
	return GetChildren(true);
}

std::vector<e2d::Entity*> e2d::Entity::GetChildren(bool needExist) const
{
	std::vector<e2d::Entity*> res;

	for (auto it : m_Children)
	{
		bool exist = it->ExistCalculate();
		if ((needExist && exist) || !needExist)
		{
			res.push_back(it.get());
		}
	}

	return res;
}



bool e2d::Entity::HasParent() const
{
	return m_Parent;
}

bool e2d::Entity::HasChild() const
{
	return m_ChildrenMap.size();
}

bool e2d::Entity::HasChild(const std::string& uuid) const
{
	return m_ChildrenMap.find(uuid) != m_ChildrenMap.end();
}

void e2d::Entity::RegisterChild(std::shared_ptr<e2d::Entity> child)
{
	m_ChildrenMap[child->m_UUID] = child;
}

bool e2d::Entity::SnatchEntityAsChild(const std::string& uuid)
{
	bool flag = m_Scene->HasEntity(uuid);

	if (!flag)
	{
		ztclog::info("failed find entity");
		return false;
	}

	auto entity = m_Scene->GetEntity(uuid);
	return SnatchEntityAsChild(entity);
}

bool e2d::Entity::SnatchEntityAsChild(std::shared_ptr<e2d::Entity> entity)
{
	if (IsGrandChildOf(entity.get()))
	{
		ztclog::info("entity %s is grand father of %s", entity->m_Name.c_str(), m_Name.c_str());
		return false;
	}

	entity->DisappearFromParentChildren();

	AddChild(entity);

	return false;
}

void e2d::Entity::DisappearFromParentChildren()
{
	if (m_Parent)
	{
		m_Parent->RemoveChildren({ this->m_UUID });
	}
	else
	{
		m_Scene->RemoveChidren({this->m_UUID});

	}
}

void e2d::Entity::AddChild(std::shared_ptr<e2d::Entity> child)
{
	child->m_Parent = this;
	child->m_Scene = this->m_Scene;
	this->m_Children.push_back(child);

}

bool e2d::Entity::RemoveChild(const std::string& uuid)
{
	return RemoveChildren({ uuid });
}

bool e2d::Entity::RemoveChildren(const std::vector<std::string>& uuids)
{
	std::vector<std::shared_ptr<e2d::Entity>> newChildren;

	int index = 0;
	for (auto child : m_Children)
	{
		if (UUIDsContain(uuids, child->m_UUID))
		{
			index++;
		}
		else
		{
			newChildren.push_back(child);
		}
	}

	if (index > 0)
	{
		ztclog::info("removed children num is %d", index);
		this->m_Children = newChildren;
	}
	else
	{
		ztclog::info("new child should be remove");
	}
	return index > 0;
}


std::shared_ptr<e2d::Entity> e2d::Entity::NewChild()
{
	auto child = m_Scene->NewEntity();
	child->m_Parent = this;
	child->m_Scene = m_Scene;
	this->m_Children.push_back(child);

	return child;
}

void e2d::Entity::UploadChildrenMap()
{
	m_ChildrenMap.clear();

	for (auto it : m_ChildrenMap)
	{
		RegisterChild(it.second);
	}
}


bool e2d::Entity::ExistCalculate() const
{
	if (m_Parent == 0)
	{
		return m_Exist;
	}
	return m_Exist && m_Parent->ExistCalculate();
}

bool e2d::Entity::IsGrandChildOf(e2d::Entity* other) const
{
	auto parent = this->m_Parent;

	while (parent != 0)
	{
		if (parent == other)
		{
			return true;
		}
		parent = parent->m_Parent;

	}
	return false;
}

